package express.middle;

import express.IExpressCalculate;
import express.constant.OperatorEnum;

import java.math.BigDecimal;
import java.util.List;

/**
 * 中缀表达式计算
 *
 * @author miweidong
 * @date 2021-08-10 14:20
 */
public class MiddleExpressCalculate implements IExpressCalculate {

    /**
     * 假设表达式合法，计算
     *
     * @param words 字符集
     * @return 计算结果
     */
    @Override
    public BigDecimal calculate(List<String> words) {
        if (words.size() == 0) {
            return BigDecimal.ZERO;
        }
        // 结束符
        words.add("=");
        for (String word : words) {
            OperatorEnum operatorEnum = OperatorEnum.getOperatorEnumBySymbol(word);
            if (isNumber(operatorEnum)) {
                NUMBERSTACK.push(new BigDecimal(word));
            } else {
                // 判断优先级
                while (!comparePrimary(operatorEnum) && !SYMBOLSTACK.empty()) {
                    // 计算
                    BigDecimal b = NUMBERSTACK.pop();
                    BigDecimal a = NUMBERSTACK.pop();
                    String operator = SYMBOLSTACK.pop();
                    mathematical(a, b, OperatorEnum.getOperatorEnumBySymbol(operator));
                }
                // 如果是左括号，直接入栈，如果不等于=号，操作符入栈
                if (!OperatorEnum.EQUALS.equals(operatorEnum)) {
                    SYMBOLSTACK.push(word);
                    if (OperatorEnum.RIGHT_PARENTHESES.equals(operatorEnum)) {
                        SYMBOLSTACK.pop();
                        SYMBOLSTACK.pop();
                    }
                }
            }
        }
        return NUMBERSTACK.pop();
    }

    /**
     * 比较优先级：如果当前运算符比栈顶元素运算符优先级高则返回true，否则返回false
     *
     * @param symbol 运算符
     * @return 优先级比较结果
     */
    @Override
    public Boolean comparePrimary(OperatorEnum symbol) {
        // 空栈返回ture
        if (SYMBOLSTACK.empty()) {
            return true;
        }
        String top = SYMBOLSTACK.peek();
        OperatorEnum operatorTopSymbol = OperatorEnum.getOperatorEnumBySymbol(top);
        if (OperatorEnum.LEFT_PARENTHESES.equals(operatorTopSymbol)) {
            return true;
        }
        // 比较优先级
        switch (symbol) {
            // 优先级最高
            case LEFT_PARENTHESES:
            case MULTIPLY:
            case DIVIDE:
                return true;
            case ADD:
            case SUBTRACT:
            case RIGHT_PARENTHESES:
            case EQUALS:
                return false;
            default:
                break;
        }
        return true;
    }
}
